package ai.phase.cognition.development;
import ai.algorithms.interruptible.*;
import java.util.*;
import ai.*;
public class RegionModel implements ChoiceNode {

	private Hashtable<Integer, RegionModel> j_RegionActionMap;
	private int j_RegionIndex;
	private boolean j_GoalRegionP;
	private LinkedList<Integer> j_ActionPointerList;
	private int j_ActionIndex=0;
	private Comparator<Integer> j_SortComparator;
	private RegionModel j_CurrentGoalRegion;
	private Integer[] j_SortedActionPerferences;
	private boolean j_UseRelativeScoreP=true;
	public RegionStatCollector VisitStats;
	private int j_Utility=0;
	private boolean j_Virtual=false;
	private int j_PreviousAction;
	
	public RegionModel(int regionIndex)
	{
		j_RegionIndex=regionIndex;
		j_GoalRegionP=false;
		j_RegionActionMap = new Hashtable<Integer, RegionModel>();
		VisitStats = new RegionStatCollector();
		j_Virtual=false;
	}
	
	public RegionModel()
	{
		j_RegionIndex=-1;
		j_GoalRegionP=false;
		j_RegionActionMap = new Hashtable<Integer, RegionModel>();
		VisitStats = new RegionStatCollector();
		j_Virtual=true;
	}
	
	public void SetRegionIndex(Integer index)
	{
		j_RegionIndex=index;
		j_Virtual=false;
	}
	
	public void SetVirtual()
	{
		j_Virtual=true;
	}
	
	public boolean IsVirtual()
	{
		return j_Virtual;
	}
	
	public void SetCurrentGoalRegion(RegionModel goal)
	{
		j_CurrentGoalRegion=goal;
		UpdateSortOrder();
	}
	
	public int GetUtility()
	{
		return j_Utility;
	}
	
	public void SetUtility(int utility)
	{
		j_Utility=utility;
	}
	
	private void UpdateSortOrder()
	{
		UpdateComparator();
		j_SortedActionPerferences=j_ActionPointerList.toArray(new Integer[0]);
		Arrays.sort(j_SortedActionPerferences,j_SortComparator);
	}
	
	
	// This is an abstraction for the region with the highest likelihood of leading to positive
	// stim.  This method is an iterator over the preferred next Regions
	public ChoicePointer NextChoice()
	{
		if (j_ActionIndex<j_ActionPointerList.size())
		{
			Integer actionIndex=j_SortedActionPerferences[j_ActionIndex];
			j_ActionIndex++;
			return new ActionPointer(j_RegionActionMap.get(actionIndex), (int)actionIndex);
		}
		else
			return null;
	}
	
	// Resets
	public void ResetNode()
	{
		
		j_ActionIndex=0;
	}
	
	// Indicates whether the desired goal node has been reached
	public boolean GoalReachedP()
	{
		return j_GoalRegionP;
	}
	
	public void SetActionRegionMap(int actionIndex, RegionModel newRegion)
	{
		j_RegionActionMap.put(new Integer(actionIndex), newRegion);
	}
	
	public void AddRegionToGoalSet()
	{
		j_GoalRegionP=true;
	}
	
	public void RemoveRegionFromGoalSet()
	{
		j_GoalRegionP=false;
	}
	

	// If using relative scoring then the method SetCurrentGoalRegion must have been called
	public void UpdateComparator()
	{
		if (j_UseRelativeScoreP)
			SetRelativeComparator();
		else
			SetAbsoluteComparator();
	}
	
	private void SetRelativeComparator()
	{
		j_SortComparator = new Comparator<Integer>()
		{
			public int compare(Integer i1, Integer i2)
			{
				//return r1.GetRelativeScore()-r2.GetRelativeScore();
				return GetScore(i1)-GetScore(i2);
			}
			
			public boolean equals(Object obj)
			{
				return GetScore((Integer)obj)==0;
			}
			
			private int GetScore(Integer id)
			{
				return (j_RegionActionMap.get(id)).GetRelativeScore();
			}
		};
	}
	
	private void SetAbsoluteComparator()
	{
		j_SortComparator = new Comparator<Integer>()
		{
			public int compare(Integer i1, Integer i2)
			{
				//return r1.GetRelativeScore()-r2.GetRelativeScore();
				return GetScore(i1)-GetScore(i2);
			}
			
			public boolean equals(Object obj)
			{
				return GetAbsoluteScore()==GetScore((Integer)obj);
			}
			
			private int GetScore(Integer id)
			{
				return (j_RegionActionMap.get(id)).GetAbsoluteScore();
			}
		};
	}
	
	// This score is based on the genome of the Agent
	public int GetAbsoluteScore()
	{
		return 0;
	}
	
	// This is a rough similarity measure between the goal RegionModel and this RegionModel
	public int GetRelativeScore()
	{
		// Temporarily set this to the difference in absolute scores
		return Math.abs(GetAbsoluteScore()-j_CurrentGoalRegion.GetAbsoluteScore());
	}
	
	public RegionModel GetMappedRegion(Integer actionIndex)
	{
		return j_RegionActionMap.get(actionIndex);
	}
}
